package sugarmix

import java.sql.ResultSet
import java.io.BufferedReader
import com.burtbeckwith.grails.plugin.datasources.DatasourcesUtils
import groovy.xml.MarkupBuilder
import groovy.sql.Sql

class MatcherController {
	
	Sql sql3 = new Sql(DatasourcesUtils.getDataSource('ds3'))
	Sql sql2 = new Sql(DatasourcesUtils.getDataSource('ds2'))
	
	def SBsugars = [sequence:[], id:[], species:[]]
	def GSsugars = [sequence:[], uniprotNum:[], species:[], tissue:[system:[], division1:[], division2:[], division3:[], division4:[]], glycodbNumber:[], glycanType:[], glycodbAttachedTo:[]]


/********
 * MAIN *
 ********/
	def index = {}

	
	def fullDBMatching = { 
		sql3.eachRow('select distinct on (ligand_id) * from nomenclature',
			{	SBsugars.sequence.add(it.std_nomenclature);
				SBsugars.id.add(it.ligand_id)	})
		
		for (int i = 0; i < SBsugars.sequence.size(); i++) {
			sql3.eachRow('select pathogen_name from pathogen p left join binding b on p.pathogen_id = b.pathogen_id where b.ligand_id = ?',[SBsugars.id[i]],
				{	SBsugars.species[i] = it.pathogen_name	})
		}

		sql2.eachRow('select * from glycsftw."main_glycodb" order by "SPECIES"',
			{	GSsugars.sequence.add(it."GLYCAN_ST");
				GSsugars.uniprotNum.add(it."SWISS_PROT");
				GSsugars.species.add(it."SPECIES");
				GSsugars.tissue.system.add(it."SYSTEM");
				GSsugars.tissue.division1.add(it."DIVISION1");
				GSsugars.tissue.division2.add(it."DIVISION2");
				GSsugars.tissue.division3.add(it."DIVISION3");
				GSsugars.tissue.division4.add(it."DIVISION4");
				GSsugars.glycodbNumber.add(it."GLYCODB_NO");
				GSsugars.glycanType.add(it."GLYCAN_TYPE");
				GSsugars.glycodbAttachedTo.add(it."PROTEIN_NAME")	})

		compute()

/*
 * count the number of sequences that have 1, 2 or 3+ sugars
 * 
int x=0
for(int j=0;j<GSsugars.sequence.size();j++){
	if(GSsugars.sequence[j].count(")")==0){
		x++
	}
}
println "x (1 sugar) = " + x

int x2=0
for(int j=0;j<GSsugars.sequence.size();j++){
	if(GSsugars.sequence[j].count(")")==1){
		x2++
	}
}
println "x (2 sugar) = " + x2

int x3=0
for(int j=0;j<GSsugars.sequence.size();j++){
	if(GSsugars.sequence[j].count(")")>=2){
		x3++
	}
}
println "x (3 sugar+) = " + x3

int y=0
for(int j=0;j<SBsugars.sequence.size();j++){
	//If there is only one sugar : 1-there yon'e be a ) in the string, 2-a ) followed by Cer, 3-a ) followed by the end of the string
	if((SBsugars.sequence[j].count("(")==0) || (SBsugars.sequence[j].count("(")==1) && ((SBsugars.sequence[j].count(")")==0) || (SBsugars.sequence[j]=~/\)$/) || (SBsugars.sequence[j]=~/\)Cer$/)) || ((SBsugars.sequence[j].count(")")==2) && (SBsugars.sequence[j].count(")(")==1))){
		y++
	}
}
println "y (1 sugar) = " + y

int y2=0
for(int j=0;j<SBsugars.sequence.size();j++){
	if(((SBsugars.sequence[j].count(")")==1) && (SBsugars.sequence[j].count("Cer")==0)  && (SBsugars.sequence[j]=~/\w$/)) || ((SBsugars.sequence[j].count(")")==2) && ((SBsugars.sequence[j].count(")(")==0) && ((SBsugars.sequence[j]=~/\)$/) || (SBsugars.sequence[j].count("Cer")==1)))) || ((SBsugars.sequence[j].count(")")==3) && (SBsugars.sequence[j].count(")(")==1)) ){
		y2++
	}
}
println "y (2 sugar) = " + y2

int y3=0
for(int j=0;j<SBsugars.sequence.size();j++){
	//!SBsugars.sequence[j]=~/\)Cer/
	if((SBsugars.sequence[j].count(")")>3) || ((SBsugars.sequence[j].count(")")==2) && (SBsugars.sequence[j].count("Cer")==0) && (SBsugars.sequence[j]=~/\w$/) && (SBsugars.sequence[j].count(")(")==0)) || ((SBsugars.sequence[j].count(")")==3) && (SBsugars.sequence[j].count(")(")==0))){
		y3++
	}
}
println "y (3 sugar+) = " + y3
*/

	}


	def selectSBInput = {}

	def saveSBInput = {
		//handle uploaded file
		String sSB=request.getFile('SBfile').inputStream.text

		sSB.toString().split(/\\n/).each {
			List SBInputList = []
			it.split(/\;/).each { SBInputList.add(it) }
			if(SBInputList.size()!=3){
				//error
			}
			else{
				SBsugars.sequence.add(SBInputList[0])
				SBsugars.id.add(SBInputList[1])
				SBsugars.species.add(SBInputList[2])
			}
println "haha "+ SBsugars.sequence[0] 
		}


/*		def uploadedSBFile=request.getFile('SBfile')
		if(!uploadedSBFile.empty){

			
			

			BufferedReader buffRdrSB = new BufferedReader(uploadedSBFile)
			StringBuilder sbSB = new StringBuilder()
			String sSB
			//get data from the input file
			while((sSB = buffRdrSB.readLine()) != null){
				sbSB.append(sSB)
				List SBInputList = []
				sbSB.toString().split(/\;/).each { SBInputList.add(it) }
				if(SBInputList.size()!=3){
					//error
				}
				else{
					SBsugars.sequence.add(SBInputList[0])
					SBsugars.id.add(SBInputList[1])
					SBsugars.species.add(SBInputList[2])
				}
	
			}

		}

		uploadedSBFile.close()
*/		
		sql2.eachRow('select * from glycsftw."main_glycodb" ',
			{	GSsugars.sequence.add(it."GLYCAN_ST");
				GSsugars.uniprotNum.add(it."SWISS_PROT");
				GSsugars.species.add(it."SPECIES");
				GSsugars.tissue.system.add(it."SYSTEM");
				GSsugars.tissue.division1.add(it."DIVISION1");
				GSsugars.tissue.division2.add(it."DIVISION2");
				GSsugars.tissue.division3.add(it."DIVISION3");
				GSsugars.tissue.division4.add(it."DIVISION4");
				GSsugars.glycodbNumber.add(it."GLYCODB_NO");
				GSsugars.glycanType.add(it."GLYCAN_TYPE");
				GSsugars.glycodbAttachedTo.add(it."PROTEIN_NAME")	})

		compute()
	}


	def selectGSInput = {}
	
	def saveGSInput = {
		//handle uploaded file
		def uploadedGSFile=request.getFile('GSfile')
		if(!uploadedGSFile.empty){
			println "Class: ${uploadedGSFile.class}"
			println "Name: ${uploadedGSFile.name}"
			println "OriginalFileName: ${uploadedGSFile.originalFilename}"
			println "Size: ${uploadedGSFile.size}"
			println "ContentType: ${uploadedGSFile.contentType}"
		}

		def buffRdrGS = new BufferedReader(uploadedGSFile)
		String sGS
		//get data from the input file
		while((sGS = buffRdrGS.readLine()) != null){
			List GSInputList = []
			sGS.split(/\;/).each { GSInputList.add(it) }
			if(GSInputList.size()!=11){
				//error
			}
			else{
				GSsugars.sequence.add(GSInputList[0])
				GSsugars.uniprotNum.add(GSInputList[1])
				GSsugars.species.add(GSInputList[2])
				GSsugars.tissue.system.add(GSInputList[3])
				GSsugars.tissue.division1.add(GSInputList[4])
				GSsugars.tissue.division2.add(GSInputList[5])
				GSsugars.tissue.division3.add(GSInputList[6])
				GSsugars.tissue.division4.add(GSInputList[7])
				GSsugars.glycodbNumber.add(GSInputList[8])
				GSsugars.glycanType.add(GSInputList[9]);
				GSsugars.glycodbAttachedTo.add(GSInputList[10])
			}
			
		}
		uploadedGSFile.close()

		sql3.eachRow('select distinct on (ligand_id) * from nomenclature',
			{	SBsugars.sequence.add(it.std_nomenclature);
				SBsugars.id.add(it.ligand_id)	})
		
		for (int i = 0; i < SBsugars.sequence.size(); i++) {
			sql3.eachRow('select pathogen_name from pathogen p left join binding b on p.pathogen_id = b.pathogen_id where b.ligand_id = ?',[SBsugars.id[i]],
				{	SBsugars.species[i] = it.pathogen_name	})
		}

		compute()
	}


/***********
* COMPUTE *
***********/
	def compute(){

		String SBspecies
		int totalMatch = 0
		int positivMatch = 0

		// output file
		def foo = new FileWriter('/tmp/sugarmixOutput.xml')
		def fooTxt = new FileWriter('/tmp/sugarmixOutput.csv')
		def out = new BufferedWriter(fooTxt)

/*******************************************************************************
		//GS attachment vs SB id

		def GSattachment =	[]
		def matTxt = new FileWriter('/tmp/sugarmixOutputMatrix.csv')
		def matrixOut = new BufferedWriter(matTxt)
		
		sql2.eachRow('select distinct "PROTEIN_NAME" from glycsftw."main_glycodb" ',
			{	GSattachment.add(it."PROTEIN_NAME")	})
		
		def GSattachment_SBid_Matrix = new Object[GSattachment.size()][SBsugars.id.size()]
		for (int GSa = 0; GSa < GSattachment.size(); GSa++) {
			for (int SBi = 0; SBi < SBsugars.id.size(); SBi++) {
				GSattachment_SBid_Matrix[GSa][SBi]=0
			}

//*******************************************************************************
		//SB species vs GS id
		
		def SBspeciex = []
		def matTxt2 = new FileWriter('/tmp/sugarmixOutputMatrix2.csv')
		def matrixOut2 = new BufferedWriter(matTxt2)

		sql3.eachRow('select distinct pathogen_name from pathogen ',
			{	SBspeciex.add(it.pathogen_name)	})

		def SBspeciex_GSaccessionNb_Matrix = new Object[SBspeciex.size()][GSsugars.glycodbNumber.size()]
		for (int SBs = 0; SBs < SBspeciex.size(); SBs++) {
			for (int GSj = 0; GSj < GSsugars.glycodbNumber.size(); GSj++) {
				SBspeciex_GSaccessionNb_Matrix[SBs][GSj]=0
			}
		}
*******************************************************************************
		//SB species vs GS species (count + epitope)
		
		def SBspeciex = []
			sql3.eachRow('select distinct pathogen_name from pathogen ',
			{	SBspeciex.add(it.pathogen_name)	})
				
		def matTxt3 = new FileWriter('/tmp/sugarmixOutputMatrix3.csv')
		def matrixOut3 = new BufferedWriter(matTxt3)

		def SBspeciex_GSspecies_Matrix = new Object[SBspeciex.size()][GSsugars.species.size()]
		for (int SBs = 0; SBs < SBspeciex.size(); SBs++) {
			for (int GSs = 0; GSs < GSsugars.species.size(); GSs++) {
				SBspeciex_GSspecies_Matrix[SBs][GSs]=0
			}
		}
/*******************************************************************************
		//SB id vs GS tissue
		
		def GStissue=[]
		def matTxt4 = new FileWriter('/tmp/sugarmixOutputMatrix4.csv')
		def matrixOut4 = new BufferedWriter(matTxt4)
		
		sql2.eachRow('select distinct "SYSTEM" from glycsftw."main_glycodb" ',
			{	GStissue.add(it."SYSTEM")	})
	
		def GStissue_SBid_Matrix = new Object[GStissue.size()][SBsugars.id.size()]
		for (int GSa = 0; GSa < GStissue.size(); GSa++) {
			for (int SBi = 0; SBi < SBsugars.id.size(); SBi++) {
				GStissue_SBid_Matrix[GSa][SBi]=0
			}
		}
*******************************************************************************/

		for (int j = 0; j < GSsugars.sequence.size(); j++) {
			for (int i = 0; i < SBsugars.sequence.size(); i++) {

				totalMatch++
//count
println totalMatch


				//calculation of the result
				Map result = match(i,j)
println result

/* temmp
				if(result.value[0]!=null){
					BigDecimal dd = (new BigDecimal(result.value[0])).setScale(2, BigDecimal.ROUND_HALF_UP)
					//ROUND_HALF_UP --> (0.222 = 0.22) & (0.225 = 0.23)
				}
				else{
					BigDecimal dd = 0.00
				}

				if(dd>=0.5){
temmp			*/

				if((result.value[0]>=0.9)){
					// seq >= 3sugars
					if((result.seq[0].count(")")>3) || ((result.seq[0].count(")")==2) && (result.seq[0].count("Cer")==0) && (result.seq[0]=~/\w$/) && (result.seq[0].count(")(")==0)) || ((result.seq[0].count(")")==3) && (result.seq[0].count(")(")==0))){
					// seq == 2 sugars
					//if(((result.seq[0].count(")")==1) && (result.seq[0].count("Cer")==0)  && (result.seq[0]=~/\w$/)) || ((result.seq[0].count(")")==2) && ((result.seq[0].count(")(")==0) && ((result.seq[0]=~/\)$/) || (result.seq[0].count("Cer")==1)))) || ((result.seq[0].count(")")==3) && (result.seq[0].count(")(")==1)) ){
					// seq == 1 sugar
					//if((SBsugars.sequence[j].count("(")==0) || (SBsugars.sequence[j].count("(")==1) && ((SBsugars.sequence[j].count(")")==0) || (SBsugars.sequence[j]=~/\)$/) || (SBsugars.sequence[j]=~/\)Cer$/)) || ((SBsugars.sequence[j].count(")")==2) && (SBsugars.sequence[j].count(")(")==1))){
							
		
/*temmp */				BigDecimal dd = (new BigDecimal(result.value[0])).setScale(2, BigDecimal.ROUND_HALF_UP)

						if(result.value[0]>0){
							positivMatch++
						}
		
		
						/* Matrix fullfilment */
						/*******************************************************************************
						//GS attachment vs SB id
						for (int GSa = 0; GSa < GSattachment.size(); GSa++) {
							if(GSattachment[GSa]==GSsugars.glycodbAttachedTo[j]){
								GSattachment_SBid_Matrix[GSa][i]++
							}
						}
						/*******************************************************************************
						//SB species vs GS id
						for (int SBs = 0; SBs < SBspeciex.size(); SBs++) {
							if(SBspeciex[SBs]==SBsugars.species[i]){
								SBspeciex_GSaccessionNb_Matrix[SBs][j]++
							}
						}
						*******************************************************************************
						//SB species vs GS species (count + epitope)
						for (int SBs = 0; SBs < SBspeciex.size(); SBs++) {
							if(SBspeciex[SBs]==SBsugars.species[i]){
								SBspeciex_GSspecies_Matrix[SBs][j]++
							}
						}
						/*******************************************************************************
						//SB id vs GS tissue
						for (int GSa = 0; GSa < GStissue.size(); GSa++) {
							if(GStissue[GSa]==GSsugars.tissue.system[j]){
								GStissue_SBid_Matrix[GSa][i]++
							}
						}
						*******************************************************************************/




						def writer = new StringWriter()
						def builder = new MarkupBuilder(writer)
						builder.doubleQuotes=true
			
						builder.sugarmix(matching:totalMatch){
							Glycosuite(entry:GSsugars.glycodbNumber[j]){
								GS_sequence(GSsugars.sequence[j])
							}
							Sugarbind(entry:i){
								SB_sequence(SBsugars.sequence[i])
							}
							Result(){
								Score(dd)
								Epitope(result.seq[0])
							}
						}
						foo.write(writer.toString())
		
						//csv output
						out.write(GSsugars.glycodbNumber[j] + ";" + GSsugars.glycodbAttachedTo[j] + ";" + GSsugars.sequence[j] + ";" + GSsugars.tissue.system[j] + ";" + GSsugars.glycanType[j] + ";" + SBsugars.id[i] + ";" + SBsugars.species[i] + ";" + SBsugars.sequence[i] + ";" + dd + ";" + result.seq[0] + "\n")
					}
				}
			}
		}

/*******************************************************************************
		/////////////////////////////////////////////////////////////
				//GS attachment vs SB id
		/////////////////////////////////////////////////////////////
		
				def columnFiled = []
				def lineFiled = []
				for(int GSa = 0; GSa < GSattachment.size(); GSa++){
					boolean nullLine=true
					//if one line is fully fill by 0, we don't care about it and we won't write it
					for(int SBii = 0; SBii < SBsugars.id.size(); SBii++){
						if(GSattachment_SBid_Matrix[GSa][SBii]!=0){
							nullLine=false
						}
					}
					if(nullLine==false){
						lineFiled.add(GSa)
					}
				}
				for(int SBi = 0; SBi < SBsugars.id.size(); SBi++){
					boolean nullColumn=true
					//if one column is fully fill by 0, we don't care about it and we won't write it
					for(int GSaa = 0; GSaa < GSattachment.size(); GSaa++){
						if(GSattachment_SBid_Matrix[GSaa][SBi]!=0){
							nullColumn=false
						}
					}
					if(nullColumn==false){
						columnFiled.add(SBi)
					}
				}
				matrixOut.write(";")
				for(int SBi = 0; SBi < columnFiled.size(); SBi++){
					matrixOut.write(SBsugars.id[columnFiled[SBi]] + ";")
				}
				matrixOut.write("\n")
				for(int GSa = 0; GSa < lineFiled.size(); GSa++){
					matrixOut.write(GSattachment[lineFiled[GSa]]+";")
					for(int SBi = 0; SBi < columnFiled.size(); SBi++){
						matrixOut.write(GSattachment_SBid_Matrix[lineFiled[GSa]][columnFiled[SBi]]+";")
					}
					matrixOut.write("\n")
				}

		/////////////////////////////////////////////////////////////
				//SB species vs GS id
		/////////////////////////////////////////////////////////////

				def columnFiled2 = []
				def lineFiled2 = []
				for(int GSj = 0; GSj < GSsugars.glycodbNumber.size(); GSj++){
					boolean nullColumn=true
					//if one line is fully fill by 0, we don't care about it and we won't write it
					for(int SBss = 0; SBss < SBspeciex.size(); SBss++){
						if(SBspeciex_GSaccessionNb_Matrix[SBss][GSj]!=0){
							nullColumn=false
						}
					}
					if(nullColumn==false){
						columnFiled2.add(GSj)
					}
				}
				for(int SBs = 0; SBs < SBspeciex.size(); SBs++){
					boolean nullLine=true
					//if one column is fully fill by 0, we don't care about it and we won't write it
					for(int GSjj = 0; GSjj < GSsugars.glycodbNumber.size(); GSjj++){
						if(SBspeciex_GSaccessionNb_Matrix[SBs][GSjj]!=0){
							nullLine=false
						}
					}
					if(nullLine==false){
						lineFiled2.add(SBs)
					}
				}
				matrixOut2.write(";")
				for(int GSj = 0; GSj < columnFiled2.size(); GSj++){
					matrixOut2.write(GSsugars.glycodbNumber[columnFiled2[GSj]] + ";")
				}
				matrixOut2.write("\n")
				for(int SBs = 0; SBs < lineFiled2.size(); SBs++){
					matrixOut2.write(SBspeciex[lineFiled2[SBs]]+";")
					for (int GSj = 0; GSj < columnFiled2.size(); GSj++) {
						matrixOut2.write(SBspeciex_GSaccessionNb_Matrix[lineFiled2[SBs]][columnFiled2[GSj]]+";")
					}
					matrixOut2.write("\n")
				}
******************************************************************************
		/////////////////////////////////////////////////////////////
				//SB species vs GS species (count + epitope)
		/////////////////////////////////////////////////////////////

				def columnFiled3 = []
				def lineFiled3 = []
				for(int GSs = 0; GSs < GSsugars.species.size(); GSs++){
					boolean nullLine=true
					//if one line is fully fill by 0, we don't care about it and we won't write it
					for(int SBss = 0; SBss < SBspeciex.size(); SBss++){
						if(SBspeciex_GSspecies_Matrix[SBss][GSs]!=0){
							nullLine=false
						}
					}
					if(nullLine==false){
						lineFiled3.add(GSs)
					}
				}
				for(int SBs = 0; SBs < SBspeciex.size(); SBs++){
					boolean nullColumn=true
					//if one column is fully fill by 0, we don't care about it and we won't write it
					for(int GSss = 0; GSss < GSsugars.species.size(); GSss++){
						if(SBspeciex_GSspecies_Matrix[SBs][GSss]!=0){
							nullColumn=false
						}
					}
					if(nullColumn==false){
						columnFiled3.add(SBs)
					}
				}
				matrixOut3.write(";")
				for(int SBs = 0; SBs < columnFiled3.size(); SBs++){
					matrixOut3.write(SBspeciex[columnFiled3[SBs]]+";;")
				}
				boolean alreadySeen = false
				def cmpGSSpecies = GSsugars.species[0]
				int speciesIterationsNb = 0
				matrixOut3.write("\n")
				for(int GSs = 1; GSs < lineFiled3.size(); GSs++){
					if((cmpGSSpecies!=GSsugars.species[lineFiled3[GSs-1]]) || (GSs==lineFiled3.size()-1)){
						matrixOut3.write(GSsugars.species[lineFiled3[GSs]] + ";")
						for(int SBs = 0; SBs < columnFiled3.size(); SBs++){
							int totalcountspecies= 0
							for(int cpt1 = 1; cpt1 <= speciesIterationsNb; cpt1++){
								totalcountspecies = totalcountspecies + SBspeciex_GSspecies_Matrix[columnFiled3[SBs]][lineFiled3[GSs-cpt1]]
							}
							
							//SBspeciex_GSspecies_Matrix[columnFiled3[SBs]][lineFiled3[GSs]]
							matrixOut3.write(totalcountspecies+";")
							matrixOut3.write(SBsugars.sequence[columnFiled3[SBs]] + ";")
						}
						matrixOut3.write("\n")
						cmpGSSpecies = GSsugars.species[lineFiled3[GSs]]
						speciesIterationsNb=0
					}
					else{
						speciesIterationsNb++
					}
				}
/*****************************************************************************
		/////////////////////////////////////////////////////////////
				//SB id vs GS tissue
		/////////////////////////////////////////////////////////////

				
		
				def columnFiled4 = []
				def lineFiled4 = []
				for(int GSa = 0; GSa < GStissue.size(); GSa++){
					boolean nullLine=true
					//if one line is fully fill by 0, we don't care about it and we won't write it
					for(int SBii = 0; SBii < SBsugars.id.size(); SBii++){
						if(GStissue_SBid_Matrix[GSa][SBii]!=0){
							nullLine=false
						}
					}
					if(nullLine==false){
						lineFiled4.add(GSa)
					}
				}
				for(int SBi = 0; SBi < SBsugars.id.size(); SBi++){
					boolean nullColumn=true
					//if one column is fully fill by 0, we don't care about it and we won't write it
					for(int GSaa = 0; GSaa < GStissue.size(); GSaa++){
						if(GStissue_SBid_Matrix[GSaa][SBi]!=0){
							nullColumn=false
						}
					}
					if(nullColumn==false){
						columnFiled4.add(SBi)
					}
				}
				matrixOut4.write(";")
				for(int SBi = 0; SBi < columnFiled4.size(); SBi++){
					matrixOut4.write(SBsugars.id[columnFiled4[SBi]] + ";")
				}
				matrixOut4.write("\n")
				for(int GSa = 0; GSa < lineFiled4.size(); GSa++){
					matrixOut4.write(GStissue[lineFiled4[GSa]]+";")
					for(int SBi = 0; SBi < columnFiled4.size(); SBi++){
						matrixOut4.write(GStissue_SBid_Matrix[lineFiled4[GSa]][columnFiled4[SBi]]+";")
					}
					matrixOut4.write("\n")
				}
***************************************************************************** */

		// close the output file
		foo.close()
		out.close()
		fooTxt.close()
		
		//matrixOut.close()
		//matrixOut2.close()
		//matrixOut3.close()
		//matrixOut4.close()

println "fin"

render positivMatch
render " positiv matches"
//println "test(test)[toto(toto)[Man(a1-3)]]trunk".split(/\[|\]+(?=\w)/)
	}


/********************
* Matching Function *
*********************/
	Map match(i, j){

		Map score = [value:[], seq:[]]
		Map scoreRet = [value:[], seq:[]]
		float scoreTemp = 0.0
		int matchingNb = 0
		int maxScoreNb = 0
		float maxScore = 0.0
		//int percent = 0

		List mySBsugars = []
		List myGSsugars = []
		
		Map SBseq = [pos:[], rank:[], sugar:[],linkage:[],previousSugar:[]]
		Map GSseq = [pos:[], rank:[], sugar:[],linkage:[],previousSugar:[]]

		Boolean isOk = false
		boolean keepTheRank = false

		int myPos = 0
		int myPosTemp = 0
		List previousTemp = []
		int myRank = 0
		int posLastIndex = 0


/* ----------------------------------------------------------------------------- */
/* Version 1.1 */
		// GS pre-treatment
		//exception GS01 : MainSugarsSequences+"+OtherSugarSequences" ==> remove OtherSugarSequence (will be corrected in the next GS DB ?)
		if (GSsugars.sequence[j] =~ /\"$/){
			myGSsugars = GSsugars.sequence[j].split(/\[|\]+(?=\w)|\+\"\+/)
			myGSsugars.remove(myGSsugars.size()-1)
		}
		else if (GSsugars.sequence[j] !=~ /\)$/){
			//case : Gal(b1-
			if (GSsugars.sequence[j].lastIndexOf("(") > GSsugars.sequence[j].lastIndexOf(")")){
				myGSsugars.add(GSsugars.sequence[j]+")")
			}
			else{
				myGSsugars.add(GSsugars.sequence[j]+"(null)")
			}
		}
		else{
			myGSsugars.add(GSsugars.sequence[j])
		}

		// SB pre-treatment
		//exception SB01 : Ceramide is not a sugar that could be match
		if (SBsugars.sequence[i] =~ /Cer$/){
			mySBsugars = SBsugars.sequence[i].split(/Cer/)
		}
		else{
			if (SBsugars.sequence[i] !=~ /\)$/){
				//case : Gal(b
				if (SBsugars.sequence[i].lastIndexOf("(") > SBsugars.sequence[i].lastIndexOf(")")){
					mySBsugars.add(SBsugars.sequence[i]+")")
				}
				else{
					mySBsugars.add(SBsugars.sequence[i]+"(null)")
				}
			}
			else{
				mySBsugars.add(SBsugars.sequence[i])
			}
		}

//mySBsugars[0] = "Fuc(a1-4)[Man(a1-3)]Gal(b1-4)LoL(a1-3)"
//myGSsugars[0] = "Glc(a1-6)[GlcNac(a1-4)Fuc(a1-2)[Gal(b1-3)[GalNAc(b1-4)]NeuAc(a2-3)]Man(a1-3)]Gal(b1-4)LoL(a1-3)"
//mySBsugars[0] = "Fuc(a1-4)[Man(a1-3)]Gal(b1-4)LoL(a1-3)"
//myGSsugars[0] = "Fuc(a1-4)[Man(a1-3)Glc(b1-6)]Gal(b1-4)Fuc(a1-4)[Man(a1-3)]Gal(b1-4)"

		//sequencing SB
		//----------
		posLastIndex = mySBsugars[0].lastIndexOf("]")
		if(posLastIndex == -1){ //there are no ] in the sequence
			//separate sugars & linkages
				List sugarAndLinkage = []
				mySBsugars[0].split(/\)/).each{
					it.split(/\(/).each { sugarAndLinkage.add(it) }
				}

				//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
				myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

				while(sugarAndLinkage.size() > 1){
					SBseq.pos.add(myPosTemp)
					SBseq.rank.add(myRank)
					SBseq.sugar.add(sugarAndLinkage[0])
					sugarAndLinkage.remove(0)
					SBseq.linkage.add(sugarAndLinkage[0])
					sugarAndLinkage.remove(0)
					SBseq.previousSugar.add(myPosTemp-1)
					
					myPosTemp--
					myPos++
				}


		}
		else{ //sequence with branch
			def restSequence = mySBsugars[0]
			//while there are almost one branch
			while((restSequence.lastIndexOf("]") != -1) && (restSequence.lastIndexOf("[")!= -1)){
				/** ******
				* PART 1 *
				****** **/
				while(isOk == false){
					//if the sequence was like ...][...
					//restS == ....]
					//it will just put restS = .... without the char ']' at the end
					//else do
					if(restSequence.lastIndexOf("]") != restSequence.size()-1){
						def endSequence = restSequence[restSequence.lastIndexOf("]")+1..restSequence.size()-1]
							
						List sugarAndLinkage = []
						endSequence.split(/\)/).each{
							it.split(/\(/).each { sugarAndLinkage.add(it) }
						}

						//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
						myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

						while(sugarAndLinkage.size() > 1){
							SBseq.pos.add(myPosTemp)
							SBseq.rank.add(myRank)
							SBseq.sugar.add(sugarAndLinkage[0])
							sugarAndLinkage.remove(0)
							SBseq.linkage.add(sugarAndLinkage[0])
							sugarAndLinkage.remove(0)
							SBseq.previousSugar.add(myPosTemp-1)
							
							myPosTemp--
							myPos++
						}
						if(myRank > 0){
							SBseq.previousSugar[SBseq.previousSugar.size()-1] = previousTemp[myRank]
						}

						myRank++
						previousTemp[myRank] = myPos-1
					}
	
					restSequence = restSequence[0..restSequence.lastIndexOf("]")-1]

	
					// when ....]....[endS
					// or 	....][endS
					// or 	....[endS --> (lastIndexOf("]")==-1)
					// end of loop
					if(restSequence.lastIndexOf("]") < restSequence.lastIndexOf("[")){
						isOk = true
					}
				}

				isOk = false
				keepTheRank = true

				/** ******
				* PART 2 *
				****** **/
				//in the other case we have to treat the rest
				while(isOk == false){
					def endSequence = restSequence[restSequence.lastIndexOf("[")+1..restSequence.size()-1]
					
					List sugarAndLinkage = []
					endSequence.split(/\)/).each{
						it.split(/\(/).each { sugarAndLinkage.add(it) }
					}


					//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
					myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)
	
					while(sugarAndLinkage.size() > 1){
						SBseq.pos.add(myPosTemp)
						SBseq.rank.add(myRank)
						SBseq.sugar.add(sugarAndLinkage[0])
						sugarAndLinkage.remove(0)
						SBseq.linkage.add(sugarAndLinkage[0])
						sugarAndLinkage.remove(0)
						SBseq.previousSugar.add(myPosTemp-1)
						
						myPosTemp--
						myPos++
					}
					if(myRank > 0){
						SBseq.previousSugar[SBseq.previousSugar.size()-1] = previousTemp[myRank]
					}
					restSequence = restSequence[0..restSequence.lastIndexOf("[")-1]
					myRank--
					if(keepTheRank == true){
						keepTheRank = false
						myRank++
					}

	
					// when ...[....]endS
					// or endS --> ((lastIndexOf("[")==-1))
					// end of loop
					if(restSequence.lastIndexOf("]") >= restSequence.lastIndexOf("[")){
						isOk = true
					}
				}
				isOk = false
			}
			/** ******
			* PART 3 *
			****** **/
			def endSequence = restSequence
			
			List sugarAndLinkage = []
			endSequence.split(/\)/).each{
				it.split(/\(/).each { sugarAndLinkage.add(it) }
			}


			//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
			myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

			while(sugarAndLinkage.size() > 1){
				SBseq.pos.add(myPosTemp)
				SBseq.rank.add(myRank)
				SBseq.sugar.add(sugarAndLinkage[0])
				sugarAndLinkage.remove(0)
				SBseq.linkage.add(sugarAndLinkage[0])
				sugarAndLinkage.remove(0)
				SBseq.previousSugar.add(myPosTemp-1)
				
				myPosTemp--
				myPos++
			}
			if(myRank > 0){
				SBseq.previousSugar[SBseq.previousSugar.size()-1] = previousTemp[myRank]
			}


		}




		isOk = false
		keepTheRank = false

		myPos = 0
		myPosTemp = 0
		previousTemp = []
		myRank = 0
		posLastIndex = 0



		//sequencing GS
		//----------
		posLastIndex = myGSsugars[0].lastIndexOf("]")
		if(posLastIndex == -1){ //there are no ] in the sequence
			//separate sugars & linkages
				List sugarAndLinkage = []
				myGSsugars[0].split(/\)/).each{
					it.split(/\(/).each { sugarAndLinkage.add(it) }
				}

				//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
				myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

				while(sugarAndLinkage.size() > 1){
					GSseq.pos.add(myPosTemp)
					GSseq.rank.add(myRank)
					GSseq.sugar.add(sugarAndLinkage[0])
					sugarAndLinkage.remove(0)
					GSseq.linkage.add(sugarAndLinkage[0])
					sugarAndLinkage.remove(0)
					GSseq.previousSugar.add(myPosTemp-1)

					myPosTemp--
					myPos++
				}


		}
		else{ //sequence with branch
			def restSequence = myGSsugars[0]
			//while there are almost one branch
			while((restSequence.lastIndexOf("]") != -1) && (restSequence.lastIndexOf("[")!= -1)){
				/** ******
				* PART 1 *
				****** **/
				while(isOk == false){
					//if the sequence was like ...][...
					//restS == ....]
					//it will just put restS = .... without the char ']' at the end
					//else do
					if(restSequence.lastIndexOf("]") != restSequence.size()-1){
						def endSequence = restSequence[restSequence.lastIndexOf("]")+1..restSequence.size()-1]

						List sugarAndLinkage = []
						endSequence.split(/\)/).each{
							it.split(/\(/).each { sugarAndLinkage.add(it) }
						}

						//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
						myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

						while(sugarAndLinkage.size() > 1){
							GSseq.pos.add(myPosTemp)
							GSseq.rank.add(myRank)
							GSseq.sugar.add(sugarAndLinkage[0])
							sugarAndLinkage.remove(0)
							GSseq.linkage.add(sugarAndLinkage[0])
							sugarAndLinkage.remove(0)
							GSseq.previousSugar.add(myPosTemp-1)
							
							myPosTemp--
							myPos++
						}
						if(myRank > 0){
							GSseq.previousSugar[GSseq.previousSugar.size()-1] = previousTemp[myRank]
						}

						myRank++
						previousTemp[myRank] = myPos-1
					}

					restSequence = restSequence[0..restSequence.lastIndexOf("]")-1]

					// when ....]....[endS
					// or 	....][endS
					// or 	....[endS --> (lastIndexOf("]")==-1)
					// end of loop
					if(restSequence.lastIndexOf("]") < restSequence.lastIndexOf("[")){
						isOk = true
					}
				}

				isOk = false
				keepTheRank = true

				/** ******
				* PART 2 *
				****** **/
				//in the other case we have to treat the rest
				while(isOk == false){
					def endSequence = restSequence[restSequence.lastIndexOf("[")+1..restSequence.size()-1]
					
					List sugarAndLinkage = []
					endSequence.split(/\)/).each{
						it.split(/\(/).each { sugarAndLinkage.add(it) }
					}


					//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
					myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)
	
					while(sugarAndLinkage.size() > 1){
						GSseq.pos.add(myPosTemp)
						GSseq.rank.add(myRank)
						GSseq.sugar.add(sugarAndLinkage[0])
						sugarAndLinkage.remove(0)
						GSseq.linkage.add(sugarAndLinkage[0])
						sugarAndLinkage.remove(0)
						GSseq.previousSugar.add(myPosTemp-1)
						
						myPosTemp--
						myPos++
					}
					if(myRank > 0){
						GSseq.previousSugar[GSseq.previousSugar.size()-1] = previousTemp[myRank]
					}
					restSequence = restSequence[0..restSequence.lastIndexOf("[")-1]
					myRank--
					if(keepTheRank == true){
						keepTheRank = false
						myRank++
					}

	
					// when ...[....]endS
					// or endS --> ((lastIndexOf("[")==-1))
					// end of loop
					if(restSequence.lastIndexOf("]") >= restSequence.lastIndexOf("[")){
						isOk = true
					}
				}
				isOk = false
			}

			/** ******
			* PART 3 *
			****** **/
			def endSequence = restSequence

			List sugarAndLinkage = []
			endSequence.split(/\)/).each{
				it.split(/\(/).each { sugarAndLinkage.add(it) }
			}


			//sugarAndLinkage.size()=nbSugar+nbLinkage --> nbSugar = sugarAndLinkage.size()/2 -1 --> start with 0 --> previous of the first sugar is -1
			myPosTemp = myPos + (sugarAndLinkage.size()/2 - 1)

			while(sugarAndLinkage.size() > 1){
				GSseq.pos.add(myPosTemp)
				GSseq.rank.add(myRank)
				GSseq.sugar.add(sugarAndLinkage[0])
				sugarAndLinkage.remove(0)
				GSseq.linkage.add(sugarAndLinkage[0])
				sugarAndLinkage.remove(0)
				GSseq.previousSugar.add(myPosTemp-1)
				
				myPosTemp--
				myPos++
			}
			if(myRank > 0){
				GSseq.previousSugar[GSseq.previousSugar.size()-1] = previousTemp[myRank]
			}


		}


		//Map sorting
		for(int ii=0; ii<SBseq.pos.size(); ii++){
			if(SBseq.pos[ii] != ii){
				for(int iii=0; iii<SBseq.pos.size(); iii++){
					if(SBseq.pos[iii] == ii){
						//switch pos
						def SBtemp1 = SBseq.pos[ii]
						SBseq.pos[ii] = SBseq.pos[iii]
						SBseq.pos[iii] = SBtemp1
						//switch rank
						def SBtemp2 = SBseq.rank[ii]
						SBseq.rank[ii] = SBseq.rank[iii]
						SBseq.rank[iii] = SBtemp2
						//switch sugar
						def SBtemp3 = SBseq.sugar[ii]
						SBseq.sugar[ii] = SBseq.sugar[iii]
						SBseq.sugar[iii] = SBtemp3
						//switch linkage
						def SBtemp4 = SBseq.linkage[ii]
						SBseq.linkage[ii] = SBseq.linkage[iii]
						SBseq.linkage[iii] = SBtemp4
						//switch previousSugar
						def SBtemp5 = SBseq.previousSugar[ii]
						SBseq.previousSugar[ii] = SBseq.previousSugar[iii]
						SBseq.previousSugar[iii] = SBtemp5
					}
				}
			}
		}

		for(int jj=0; jj<GSseq.pos.size(); jj++){
			if(GSseq.pos[jj] != jj){
				for(int jjj=0; jjj<GSseq.pos.size(); jjj++){
					if(GSseq.pos[jjj] == jj){
						///switch pos
						def GStemp1 = GSseq.pos[jj]
						GSseq.pos[jj] = GSseq.pos[jjj]
						GSseq.pos[jjj] = GStemp1
						//switch rank
						def GStemp2 = GSseq.rank[jj]
						GSseq.rank[jj] = GSseq.rank[jjj]
						GSseq.rank[jjj] = GStemp2
						//switch sugar
						def GStemp3 = GSseq.sugar[jj]
						GSseq.sugar[jj] = GSseq.sugar[jjj]
						GSseq.sugar[jjj] = GStemp3
						//switch linkage
						def GStemp4 = GSseq.linkage[jj]
						GSseq.linkage[jj] = GSseq.linkage[jjj]
						GSseq.linkage[jjj] = GStemp4
						//switch previousSugar
						def GStemp5 = GSseq.previousSugar[jj]
						GSseq.previousSugar[jj] = GSseq.previousSugar[jjj]
						GSseq.previousSugar[jjj] = GStemp5
					}
				}
			}
		}


		//if the SB sequence contains only 1 sugar
		if((SBseq.pos.size()==1) && (GSseq.pos.size()!=1)){
			for(int jj=0; jj<GSseq.pos.size(); jj++){
				if((SBseq.sugar[0] == GSseq.sugar[jj])){
					scoreRet.value.add(-1)
				}
			}
		}
		//if the GS sequence contains only 1 sugar
		else if((GSseq.pos.size()==1) && (SBseq.pos.size()!=1)){
			for(int ii=0; ii<GSseq.pos.size(); ii++){
				if((SBseq.sugar[ii] == GSseq.sugar[0])){
					scoreRet.value.add(-1)
				}
			}
		}
		//if the SB sequence contains more sugars than the GS sequence
		else if(SBseq.pos.size()>GSseq.pos.size()){
			scoreRet.value.add(-1)
		}		
		else{
			//for each sugar from sugarbind we try to check if one in glycosuite could match
			for(int ii=0; ii<SBseq.pos.size(); ii++){
				for(int jj=0; jj<GSseq.pos.size(); jj++){
					//if yes
					if((SBseq.sugar[ii] == GSseq.sugar[jj])){
						//the goal of this loop is to find the next sugar after the first matching, in both sequence
						score.seq[matchingNb]=""
						score.value[matchingNb]=0
						for(int x=ii; x<SBseq.pos.size(); x++){
							for(int y=jj; y<GSseq.pos.size(); y++){
								//and we call the function with these positions
								if((SBseq.previousSugar[x] == SBseq.pos[ii]) && (GSseq.previousSugar[y] == GSseq.pos[jj])){
									scoreTemp = scoring(SBseq, GSseq, x, y, score, matchingNb, scoreTemp)
								}
							}
						}

						if(scoreTemp > 0){
							
							// the final score will be calculated in function of the full GS seq
							float totalGSscore = 0.0
						
							for(int jjj=0; jjj<GSseq.pos.size(); jjj++){
								def weight = 1.0
				
								switch (GSseq.rank[jjj]) {
								case 0:
									weight = 0.1
									break;
								case 1:
									weight = 1.0
									break;
								case 2:
									weight = 10.0
									break;
								case 3:
									weight = 100.0
									break;
								case 4:
									weight = 1000.0
									break;
								case 5:
									weight = 10000.0
									break;
								default:
									weight = 1.0
									break;
								}
								totalGSscore = totalGSscore + 1*weight
							}
										

							score.seq[matchingNb]=score.seq[matchingNb]+SBseq.sugar[ii]
							//score over 1, depending of the proportion of the GSseq recognised
							score.value[matchingNb]=scoreTemp/totalGSscore
							matchingNb++
						}
						else{
							score.seq.remove(matchingNb)
						}

						//keep the max score found between these 2 sequences
						if(scoreTemp > maxScore){
							maxScore = scoreTemp
							maxScoreNb = matchingNb-1
						}

						scoreTemp = 0.0
					}
				}
			}
		}
/*
println "score final " + maxScore
println matchingNb
println score
*/

		if((score.seq[maxScoreNb].toString().count(")")+1) == SBseq.pos.size()){
			scoreRet.value.add(1.00)
			scoreRet.seq.add(SBsugars.sequence[i])
		}
		else{
			scoreRet.value.add(score.value[maxScoreNb])
			scoreRet.seq.add(score.seq[maxScoreNb])
		}

		return scoreRet
	}


/*****************
* Score Function *
******************/
//
	float scoring(SBseq, GSseq, i, j, score, matchingNb, scoreTemp){
		
		float weight = 1.0
		
		//if the following sugar is matching we can count it
		if((SBseq.sugar[i] == GSseq.sugar[j]) && (SBseq.linkage[i] == GSseq.linkage[j])){
			switch (GSseq.rank[j]) {
			//if the matching is on the tail : penality
			case 0:
				weight = 0.1
				break;
			case 1:
				weight = 1.0
				break;
			case 2:
				weight = 10.0
				break;
			case 3:
				weight = 100.0
				break;
			case 4:
				weight = 1000.0
				break;
			case 4:
				weight = 10000.0
				break;
			default:
				weight = 1.0
				break;
			}

			scoreTemp = scoreTemp + 1*weight

			score.seq[matchingNb]=SBseq.sugar[i].toString()+"("+SBseq.linkage[i].toString()+")"+score.seq[matchingNb]

			//and call recursivly the function with the positions of all the following sugar
			//it can be more than one if the first matching is before a "branch"
			for(int x=i; x<SBseq.pos.size(); x++){
				for(int y=j; y<GSseq.pos.size(); y++){
					if((SBseq.previousSugar[x] == SBseq.pos[i]) && (GSseq.previousSugar[y] == GSseq.pos[j])){
						scoreTemp = scoring(SBseq, GSseq, x, y, score, matchingNb, scoreTemp)
					}
				}
			}
		}
		return scoreTemp
	}

}
